package com.iplant.aps.serviceImpl.dao;

import com.iplant.aps.service.apsenum.aps.APSShiftPeriod;
import com.iplant.aps.service.apsenum.aps.APSTaskStatus;
import com.iplant.aps.service.po.aps.APSTaskPart;
import com.iplant.aps.service.po.aps.APSTaskPartPoint;
import com.iplant.aps.service.po.aps.gantt.APSGanttData;
import com.iplant.aps.service.po.aps.gantt.APSGanttLink;
import com.iplant.aps.service.po.oms.OMSOrder;
import com.iplant.base.po.OutResult;
import com.iplant.base.po.Pagination;
import com.iplant.base.po.enums.DBSchemas;
import com.iplant.base.po.enums.ExceptionTypes;
import com.iplant.base.utils.general.CalendarTool;
import com.iplant.base.utils.general.StringUtils;
import com.iplant.base.utils.sql.BaseDAO;
import com.iplant.basic.service.po.bms.BMSEmployee;
import com.iplant.pdm.service.po.bop.FPCRoutePart;
import com.iplant.pdm.service.po.bop.FPCRoutePartPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

public class APSTaskPartDAO extends BaseDAO {

    private static APSTaskPartDAO Instance = null;
    private static Logger logger = LoggerFactory.getLogger(APSTaskPartDAO.class);

    private APSTaskPartDAO() {
        super(APSTaskPart.class);
    }

    public static APSTaskPartDAO getInstance() {
        if (Instance == null)
            Instance = new APSTaskPartDAO();
        return Instance;
    }


    public List<APSTaskPart> GetAPSTaskPartList(BMSEmployee wLoginUser, APSShiftPeriod wAPSShiftPeriod,
                                                Calendar wStartTime, Calendar wEndTime, OutResult<Integer> wErrorCode) {

        return GetAPSTaskPartList(wLoginUser, wAPSShiftPeriod, null, wStartTime, wEndTime, wErrorCode);
    }

    public List<APSTaskPart> GetAPSTaskPartList(BMSEmployee wLoginUser, APSShiftPeriod wAPSShiftPeriod,
                                                List<Integer> wOrderIDList, OutResult<Integer> wErrorCode) {

        if (wOrderIDList == null || wOrderIDList.size() == 0)
            return new ArrayList<>();
        return GetAPSTaskPartList(wLoginUser, wAPSShiftPeriod, wOrderIDList, CalendarTool.getCalendar(2000, 0, 1),
                CalendarTool.getCalendar(2000, 0, 1), wErrorCode);

    }

    public List<APSTaskPart> GetAPSTaskPartList(BMSEmployee wLoginUser, APSShiftPeriod wAPSShiftPeriod,
                                                List<Integer> wOrderIDList, Calendar wStartTime, Calendar wEndTime,
                                                OutResult<Integer> wErrorCode) {

        Map<String, Object> wParams = new HashMap<>();
        if (wOrderIDList != null && wOrderIDList.size() > 0)
            wParams.put("OrderID", wOrderIDList);

        wParams.put("StartTime", wStartTime);
        wParams.put("EndTime", wEndTime);
        wParams.put("ShiftPeriod", wAPSShiftPeriod.getValue());
        wParams.put("Active", 1);
        return this.SelectPOList(wLoginUser, wParams, APSTaskPart.class, Pagination.getNewMaxSize(), wErrorCode);

    }

    /**
     * 获取甘特图数据
     */
    public List<APSGanttData> APS_GetAPSGanttDataList(BMSEmployee wLoginUser, List<APSTaskPart> wAPSTaskPartList,
                                                      List<OMSOrder> wOrderList, List<APSGanttLink> wAPSGanttLinkList
            , List<FPCRoutePart> wFPCRoutePartList, List<FPCRoutePartPoint> wFPCRoutePartPointList,
                                                      OutResult<Integer> wErrorCode) {
        List<APSGanttData> wResult = new ArrayList<>();
        try {
            if (wAPSTaskPartList == null || wAPSTaskPartList.size() <= 0) {
                return wResult;
            }

            String uuid = UUID.randomUUID().toString().replaceAll("-", "");

            int wGlobalID = 1;


            SimpleDateFormat wSDF = new SimpleDateFormat("dd-MM-yyyy");

            //①渲染订单甘特数据
            APSGanttData wAPSGanttData;
            APSGanttData wAPSGanttDataSon;
            APSGanttData wAPSGanttDataSonSon;
            APSGanttLink wAPSGanttLink;
            APSGanttLink wAPSGanttLinkSon;
            List<APSTaskPart> wOrderTaskPartList;
            List<APSGanttData> wOrderGanttDataList;
            for (OMSOrder wOMSOrder : wOrderList) {
                wAPSGanttData = new APSGanttData();
                wAPSGanttData.id = wGlobalID++;
                wAPSGanttData.text = wOMSOrder.Code;

                //②订单子项甘特数据
                wOrderTaskPartList =
                        wAPSTaskPartList.stream().filter(p -> p.OrderID == wOMSOrder.ID).collect(Collectors.toList());
                Calendar wMinDate =
                        wOrderTaskPartList.stream().min(Comparator.comparing(APSTaskPart::getPartStartTime)).get().PartStartTime;
                Calendar wMaxDate =
                        wOrderTaskPartList.stream().max(Comparator.comparing(APSTaskPart::getPartEndTime)).get().PartEndTime;

                wAPSGanttData.start_date = wSDF.format(wMinDate.getTime());
                wAPSGanttData.duration = String.valueOf(CalendarTool.SubDate(wMaxDate, wMinDate) + 1);
                wAPSGanttData.progress = 1;
                wAPSGanttData.open = true;
                wAPSGanttData.parent = "0";
                wAPSGanttData.orderid = wOMSOrder.ID;
                wResult.add(wAPSGanttData);
                //②订单子项甘特数据
//                wOrderTaskPartList =
//                        wAPSTaskPartList.stream().filter(p -> p.OrderID == wOMSOrder.ID).collect(Collectors.toList());
                for (APSTaskPart wAPSTaskPart : wOrderTaskPartList) {
                    wAPSGanttDataSon = new APSGanttData();
                    wAPSGanttDataSon.id = wGlobalID++;
                    wAPSGanttDataSon.text = wAPSTaskPart.RoutePartName;
                    wAPSGanttDataSon.start_date = wSDF.format(wAPSTaskPart.PartStartTime.getTime());
                    wAPSGanttDataSon.duration = String.valueOf(CalendarTool.SubDate(wAPSTaskPart.PartEndTime,
                            wAPSTaskPart.PartStartTime) + 1);
                    wAPSGanttDataSon.progress = 1;
                    wAPSGanttDataSon.open = false;
                    wAPSGanttDataSon.parent = String.valueOf(wAPSGanttData.id);
                    wAPSGanttDataSon.orderid = wOMSOrder.ID;
                    wAPSGanttDataSon.routepartid = wAPSTaskPart.RoutePartID;
                    wResult.add(wAPSGanttDataSon);
                    //③工序子项甘特数据
                    wAPSTaskPart.TaskPartPointList.sort(Comparator.comparing(APSTaskPartPoint::getRoutePartPointOrder));
                    for (APSTaskPartPoint wAPSTaskPartPoint : wAPSTaskPart.TaskPartPointList) {
                        wAPSGanttDataSonSon = new APSGanttData();
                        wAPSGanttDataSonSon.id = wGlobalID++;
                        wAPSGanttDataSonSon.text = wAPSTaskPartPoint.RoutePartPointName;
                        wAPSGanttDataSonSon.start_date = wSDF.format(wAPSTaskPartPoint.PartPointStartTime.getTime());
                        wAPSGanttDataSonSon.duration =
                                String.valueOf(CalendarTool.SubDate(wAPSTaskPartPoint.PartPointEndTime,
                                        wAPSTaskPartPoint.PartPointStartTime) + 1);
                        wAPSGanttDataSonSon.progress = 1;
                        wAPSGanttDataSonSon.open = true;
                        wAPSGanttDataSonSon.parent = String.valueOf(wAPSGanttDataSon.id);
                        wAPSGanttDataSonSon.orderid = wOMSOrder.ID;
                        wAPSGanttDataSonSon.routepartid = wAPSTaskPart.RoutePartID;
                        wAPSGanttDataSonSon.routepartpointid = wAPSTaskPartPoint.RoutePartPointID;
                        wResult.add(wAPSGanttDataSonSon);
                    }
                }
            }
            //添加工艺子项连线
            List<FPCRoutePart> wNextRoutePartList;
            APSGanttData wSourceGanttData;
            APSGanttData wTargetGanttData;
            for (APSTaskPart wAPSTaskPart : wAPSTaskPartList) {
                //添加工艺工序子项连线
                AddPartPointLinks(wAPSGanttLinkList, wResult, wAPSTaskPart.TaskPartPointList, wFPCRoutePartPointList,
                        wGlobalID);

                //周计划不连工艺
                if (wAPSTaskPart.ShiftPeriod == APSShiftPeriod.Week.getValue()) {
                    continue;
                }

                //查找后工艺
                if (wFPCRoutePartList.stream().noneMatch(p -> p.PrevPartID == wAPSTaskPart.RoutePartID)) {
                    continue;
                }

                //查找源甘特数据
                if (wResult.stream().noneMatch(p -> p.orderid == wAPSTaskPart.OrderID && p.routepartid == wAPSTaskPart.RoutePartID)) {
                    continue;
                }
                wSourceGanttData =
                        wResult.stream().filter(p -> p.orderid == wAPSTaskPart.OrderID && p.routepartid == wAPSTaskPart.RoutePartID).findFirst().get();

                wNextRoutePartList =
                        wFPCRoutePartList.stream().filter(p -> p.PrevPartID == wAPSTaskPart.RoutePartID).collect(Collectors.toList());
                for (FPCRoutePart wFPCRoutePart : wNextRoutePartList) {
                    if (wResult.stream().noneMatch(p -> p.orderid == wAPSTaskPart.OrderID && p.routepartid == wFPCRoutePart.ID)) {
                        continue;
                    }
                    wTargetGanttData =
                            wResult.stream().filter(p -> p.orderid == wAPSTaskPart.OrderID && p.routepartid == wFPCRoutePart.ID).findFirst().get();

                    wAPSGanttLink = new APSGanttLink();
                    wAPSGanttLink.id = UUID.randomUUID().toString().replaceAll("-", "");
                    wAPSGanttLink.source = String.valueOf(wSourceGanttData.id);
                    wAPSGanttLink.target = String.valueOf(wTargetGanttData.id);
                    wAPSGanttLink.type = "0";
                    wAPSGanttLinkList.add(wAPSGanttLink);
                }
            }
        } catch (Exception e) {
            logger.error("APS_GetAPSGanttDataList", e);
            wErrorCode.Result = ExceptionTypes.Exception.getValue();
        }
        return wResult;
    }

    /**
     * 添加工艺工序连线
     */
    private void AddPartPointLinks(List<APSGanttLink> wAPSGanttLinkList, List<APSGanttData> wResult,
                                   List<APSTaskPartPoint> wAPSTaskPartPointList,
                                   List<FPCRoutePartPoint> wFPCRoutePartPointList, int wGlobalID) {
        try {
            List<FPCRoutePartPoint> wNextRoutePartList;
            APSGanttData wSourceGanttData;
            APSGanttData wTargetGanttData;
            APSGanttLink wAPSGanttLink;
            for (APSTaskPartPoint wAPSTaskPartPoint : wAPSTaskPartPointList) {
                //查找后工艺
                if (wFPCRoutePartPointList.stream().noneMatch(p -> p.PrevPartPointID == wAPSTaskPartPoint.RoutePartPointID)) {
                    continue;
                }

                //查找源甘特数据
                if (wResult.stream().noneMatch(p -> p.orderid == wAPSTaskPartPoint.OrderID
                        && p.routepartid == wAPSTaskPartPoint.RoutePartID
                        && p.routepartpointid == wAPSTaskPartPoint.RoutePartPointID)) {
                    continue;
                }
                wSourceGanttData =
                        wResult.stream().filter(p -> p.orderid == wAPSTaskPartPoint.OrderID
                                && p.routepartid == wAPSTaskPartPoint.RoutePartID
                                && p.routepartpointid == wAPSTaskPartPoint.RoutePartPointID).findFirst().get();

                wNextRoutePartList =
                        wFPCRoutePartPointList.stream().filter(p -> p.PrevPartPointID == wAPSTaskPartPoint.RoutePartPointID).collect(Collectors.toList());
                for (FPCRoutePartPoint wFPCRoutePart : wNextRoutePartList) {
                    if (wResult.stream().noneMatch(p -> p.orderid == wAPSTaskPartPoint.OrderID
                            && p.routepartid == wFPCRoutePart.RoutePartID
                            && p.routepartpointid == wFPCRoutePart.ID)) {
                        continue;
                    }
                    wTargetGanttData =
                            wResult.stream().filter(p -> p.orderid == wAPSTaskPartPoint.OrderID
                                    && p.routepartid == wFPCRoutePart.RoutePartID
                                    && p.routepartpointid == wFPCRoutePart.ID).findFirst().get();

                    wAPSGanttLink = new APSGanttLink();
                    wAPSGanttLink.id = UUID.randomUUID().toString().replaceAll("-", "");
                    wAPSGanttLink.source = String.valueOf(wSourceGanttData.id);
                    wAPSGanttLink.target = String.valueOf(wTargetGanttData.id);
                    wAPSGanttLink.type = "0";
                    wAPSGanttLinkList.add(wAPSGanttLink);
                }
            }
        } catch (Exception ex) {
            logger.error("AddPartPointLinks", ex);
        }
    }


    public List<APSTaskPart> APS_SelectTaskPartList(BMSEmployee wLoginUser, Calendar wStartDate, Calendar wEndDate,
                                                    OutResult<Integer> wErrorCode) {
        Map<String, Object> wTaskPartParams = new HashMap<>();

        wTaskPartParams.put("StartTime", wStartDate);
        wTaskPartParams.put("EndTime", wEndDate);
        wTaskPartParams.put("ShiftPeriod", APSShiftPeriod.Month.getValue());
        wTaskPartParams.put("Active", 1);
        wTaskPartParams.put("Status", StringUtils.parseListArgs(APSTaskStatus.Issued.getValue(),
                APSTaskStatus.Confirm.getValue(), APSTaskStatus.Started.getValue(), APSTaskStatus.Done.getValue(),
                APSTaskStatus.Suspend.getValue()));

        List<APSTaskPart> wTaskPartList = APSTaskPartDAO.getInstance()
                .SelectPOList(wLoginUser, wTaskPartParams, Pagination.getNewMaxSize(), wErrorCode);

        if (wErrorCode.Result != 0 || wTaskPartList == null || wTaskPartList.size() == 0)
            return wTaskPartList;
        //查询子项
        wTaskPartParams.clear();

        wTaskPartParams.put("TaskPartID", wTaskPartList.stream().map(p -> p.ID).collect(Collectors.toList()));

        List<APSTaskPartPoint> wTaskPartPointList = APSTaskPartPointDAO.getInstance()
                .SelectPOList(wLoginUser, wTaskPartParams, Pagination.getNewMaxSize(), wErrorCode);

        if (wErrorCode.Result != 0 || wTaskPartPointList == null || wTaskPartPointList.size() == 0)
            return wTaskPartList;

        Map<Integer, List<APSTaskPartPoint>> wAPSTaskPartPointListMap =
                wTaskPartPointList.stream().collect(Collectors.groupingBy(p -> p.TaskPartID));

        for (APSTaskPart apsTaskPart : wTaskPartList) {
            if (!wAPSTaskPartPointListMap.containsKey(apsTaskPart.ID))
                continue;
            apsTaskPart.TaskPartPointList = wAPSTaskPartPointListMap.get(apsTaskPart.ID);
        }

        return wTaskPartList;
    }

    /**
     * 根据工位计划ID禁用派工计划
     */
    public void APS_DisableTaskSelf(BMSEmployee wLoginUser, int wTaskPartID, OutResult<Integer> wErrorCode) {
        List<String> wResult = new ArrayList<String>();
        try {
            String wSQL = StringUtils.Format("Update {0}.sfc_task_self Set Active=2,EditTime=now() " +
                            "where TaskPartID=:TaskPartID and ID>0;",
                    DBSchemas.MES.getDBName());

            Map<String, Object> wParamMap = new HashMap<String, Object>();

            wParamMap.put("TaskPartID", wTaskPartID);

            wSQL = this.DMLChange(wSQL);

            this.update(wSQL, wParamMap);
        } catch (Exception ex) {
            logger.error(ex.toString());
        }
    }

//    public static void main(String[] args) {
//
//        Calendar minTimeOfCurrentMonth = CalendarTool.getMinTimeOfCurrentMonth();
//        Calendar minTimeOfCurrentWeek = CalendarTool.getMinTimeOfCurrentWeek();
//        Calendar maxTimeOfCurrentWeek = CalendarTool.getMaxTimeOfCurrentWeek();
//        Calendar maxTimeOfCurrentMonth = CalendarTool.getMaxTimeOfCurrentMonth();
//
//        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//        String currentTime1 = sdf.format(minTimeOfCurrentMonth.getTime());
//        String currentTime2 = sdf.format(minTimeOfCurrentWeek.getTime());
//        String currentTime3 = sdf.format(maxTimeOfCurrentWeek.getTime());
//        String currentTime4 = sdf.format(maxTimeOfCurrentMonth.getTime());
//
//        System.out.println(currentTime1);
//    }
}
